﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Threading;

namespace ttg_internal.Utilities.ParameterManager.Other
{
    /// <summary>
    /// Dynamically updated converted collection
    /// </summary>
    internal class ConverterObservableCollection<T> : ReadOnlyObservableCollection<T>
    {
        /// <summary>
        /// Initializes a new instance
        /// </summary>
        public ConverterObservableCollection(Dispatcher dispatcher, IBindingList sourceCollection, ConverterDelegate converterDelegate)
            : base(new ObservableCollection<T>())
        {
            if (dispatcher == null)
            {
                throw new ArgumentNullException("dispatcher");
            }

            if (sourceCollection == null)
            {
                throw new ArgumentNullException("sourceCollection");
            }

            _converterDelegate = converterDelegate;
            _dispatcher = dispatcher;
            _sourceCollection = sourceCollection;

            SourceCollection_ListChanged(sourceCollection, new ListChangedEventArgs(ListChangedType.Reset, -1));
            _sourceCollection.ListChanged += SourceCollection_ListChanged;
        }

        // Private fields
        private readonly Dispatcher _dispatcher;
        private readonly ConverterDelegate _converterDelegate;
        private readonly IBindingList _sourceCollection;

        /// <summary>
        /// Converter delegate
        /// </summary>
        public delegate T ConverterDelegate(object source);

        /// <summary>
        /// Обрабатывает изменения исходного списка
        /// </summary>
        private void HandleListChanged(object sender, ListChangedEventArgs e)
        {
            switch (e.ListChangedType)
            {
                case ListChangedType.ItemAdded:
                    Items.Insert(e.NewIndex, _converterDelegate(_sourceCollection[e.NewIndex]));
                    break;

                case ListChangedType.ItemDeleted:
                    Items.RemoveAt(e.OldIndex);
                    break;

                case ListChangedType.ItemMoved:
                    throw new NotSupportedException("ListChangedType.ItemMoved is not supported");

                case ListChangedType.Reset:
                    Items.Clear();
                    
                    foreach (object item in _sourceCollection)
                    {
                        Items.Add(_converterDelegate(item));
                    }

                    break;

                case ListChangedType.ItemChanged:
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        private void SourceCollection_ListChanged(object sender, ListChangedEventArgs e)
        {
            _dispatcher.BeginInvoke(new ListChangedEventHandler(HandleListChanged), sender, e);
        }
    }
}
